package com.travel.travelServer.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.travel.travelServer.entity.*;
import com.travel.travelServer.entity.vo.LoginUserVO;
import com.travel.travelServer.entity.vo.UserVO;
import com.travel.travelServer.mapper.*;
import com.travel.travelServer.service.UserService;
import com.travel.travelServer.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.security.auth.Subject;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2023-10-24 16:42:09
 */
@Service
public class UserServiceImpl extends BaseService<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userDao;

    @Resource
    private UserRoleMapper userRoleDao;

    @Resource
    private RolePermissionMapper rolePermissionDao;

    @Resource
    private RoleMapper roleDao;

    @Resource
    private PermissionMapper permissionDao;

    @Resource
    private AuthenticationManager authenticationManager;

//    @Resource
//    private RedisCache redisCache;

    @Resource
    private PasswordEncoder passwordEncoder;

//    @Resource
//    private FileMa fileDao;

    @Override
    public Page<UserVO> pageByUser(Page<UserVO> page, Map<String, Object> conditions) {
        List<UserVO> userVOS = new ArrayList<>();
        Page<User> userPage = new Page<>(page.getCurrent(),page.getSize());
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq(Objects.nonNull(conditions.get("username")) && !conditions.get("username").equals("")
                ,"username", conditions.get("username"));
        userQueryWrapper.like(Objects.nonNull(conditions.get("nickName")) && !conditions.get("nickName").equals("")
                ,"nick_name", conditions.get("nickName"));
        userQueryWrapper.like(Objects.nonNull(conditions.get("gender")) && !conditions.get("gender").equals("")
                ,"gender", conditions.get("gender"));
        Page<User> dbUserPage = super.page(userPage, userQueryWrapper);
        dbUserPage.getRecords().stream().forEach(
                user -> {
                    UserVO userVO = new UserVO();
                    BeanUtils.copyProperties(user,userVO);
                    QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
                    userRoleQueryWrapper.eq("user_id",user.getId());
                    List<UserRole> userRoles = userRoleDao.selectList(userRoleQueryWrapper);
                    if (userRoles.size() > 0){
                        List<Long> roleIds = userRoles.stream().map(
                                userRole -> userRole.getRoleId()).collect(Collectors.toList());
                        if (roleIds.size() > 0){
                            List<Role> roles = roleDao.selectBatchIds(roleIds);
                            userVO.setRoles(roles);
                        }
                    }
//                    if (Objects.nonNull(user.getAvatar())){
//                        SysFile sysFile = fileDao.selectById(user.getAvatar());
//                        userVO.setFile(sysFile);
//                    }
                    userVOS.add(userVO);
                });
        page.setTotal(dbUserPage.getTotal());
        return page.setRecords(userVOS);
    }

    @Override
    public UserVO getById(Long id) {
        UserVO userVO = new UserVO();
        User dbUser = super.getById(id);
        BeanUtils.copyProperties(dbUser, userVO);
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id", id);
        List<UserRole> userRoles = userRoleDao.selectList(userRoleQueryWrapper);
        if (userRoles.size() > 0){
            List<Long> roleIds = userRoles.stream().map(
                    userRole -> userRole.getRoleId()).collect(Collectors.toList());
            if (roleIds.size() > 0){
                List<Role> roles = roleDao.selectBatchIds(roleIds);
                userVO.setRoles(roles);
            }
        }
        return userVO;
    }

    @Override
    public User getByUsername(String username) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.lambda().eq(User::getUsername,username);
        return this.getOne(userQueryWrapper);
    }

    @Override
    public Boolean saveUser(User user) {
        if (Objects.nonNull(user.getPassword())){
            String encodePassword = passwordEncoder.encode(user.getPassword());
            user.setPassword(encodePassword);
//            String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
//            //加密
//            SimpleHash simpleHash = new SimpleHash("md5", user.getPassword(), salt,1);
//            String newPassword = simpleHash.toString();
            user.setPassword(encodePassword);
//            user.setSalt(salt);
        }
        return super.save(user);
    }

    @Override
    public Boolean updateUserById(User user) {
        return super.updateById(user);
    }

    @Override
    public Boolean removeById(Long id) {
        return super.removeById(id);
    }

    @Override
    public Boolean removeByIds(List<Long> idList) {
        return super.removeByIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setRoles(List<Long> idList, Long id) {
        boolean result = false;
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id",id);
        userRoleDao.delete(userRoleQueryWrapper);
        for (Long role : idList) {
            UserRole userRole = new UserRole();
            userRole.setRoleId(role).setUserId(id);
            int row = userRoleDao.insert(userRole);
            if (row != 1){
                result = false;
            }else {
                result = true;
            }
        }
        return result;
    }

    @Override
    public ResponseData login(User user) {
        boolean isNext = false;
        LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
        userQueryWrapper.eq(User::getUsername, user.getUsername());
        User dbUser = userDao.selectOne(userQueryWrapper);
        if (Objects.isNull(dbUser)){
            return ResponseData.fail(502 ,"用户名不存在");
        }else {
            isNext = passwordEncoder.matches(user.getPassword(), dbUser.getPassword());
        }
        if (isNext){
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            if (Objects.isNull(authenticate)){
                // 未通过
                return ResponseData.fail(503 ,"登录失败");
            }
            // 通过
            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
            Long id = loginUser.getUser().getId();
            // 生成token
            String token = JWTUtils.createToken(id.toString());
            UserVO userVo = new UserVO();
            User result = userDao.selectById(id);
            BeanUtils.copyProperties(result, userVo);
            LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserRole::getUserId, result.getId());
            List<UserRole> userRoles = userRoleDao.selectList(wrapper);
            List<Role> roles = new ArrayList<>();
            for (UserRole userRole : userRoles) {
                Role role = roleDao.selectById(userRole.getRoleId());
                roles.add(role);
            }
            userVo.setRoles(roles);
            HashMap<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("user", userVo);
            // 将登录对象存入redis
//            redisUtil.set("login:" + id, loginUser);
            return ResponseData.success(map);
        }else {
            return ResponseData.fail(502 ,"密码错误");
        }
//        Subject subject = SecurityUtils.getSubject();
//        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());
//        try {
//            subject.login(usernamePasswordToken);
//            if (subject.isAuthenticated()){
//                // 通过认证
//                User userInfo = this.getByUsername(user.getUsername());
//                subject.getSession().setAttribute("userInfo",userInfo);
//                if (Objects.nonNull(userInfo)){
//                    Long id = userInfo.getId();
//                    // 生成token
//                    String token = JWTUtils.createToken(id.toString());
    //                HashMap<String, String> map = new HashMap<>();
    //                map.put("token", token);
    //
                    // 将登录对象存入redis
//                    redisCache.setCacheObject("token:" + id, token);
//                    return ResponseData.success(token);
//                }else {
//                    return null;
//                }
//            }else {
//                return null;
//            }
//        } catch (Exception e) {
//            throw new ServiceException("密码错误");
//        }
//        boolean isNext = false;
//        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//        userQueryWrapper.lambda().eq(User::getUsername, user.getUsername());
//        User dbUser = super.getOne(userQueryWrapper);
//        if (Objects.isNull(dbUser)){
//            return ResponseData.fail(501,"用户名不存在");
//        }else {
//            isNext = passwordEncoder.matches(user.getPassword(), dbUser.getPassword());
//        }
//        if (isNext){
//            UsernamePasswordAuthenticationToken authenticationToken =
//                    new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
//            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//            if (Objects.isNull(authenticate)){
//                // 未通过
//                return ResponseData.fail(500,"登录失败");
//            }
//            // 通过
//            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
//            Long id = loginUser.getUser().getId();
//            // 生成token
//            String token = JWTUtils.createToken(id.toString());
//            HashMap<String, String> map = new HashMap<>();
//            map.put("token", token);
//            // 将登录对象存入redis
//            redisCache.setCacheObject("login:" + id, loginUser);
//            return ResponseData.success(token);
//        }else {
//            return ResponseData.fail(502,"密码错误");
//        }
    }

    @Override
    public LoginUserVO getLoginUserVOById() {
        Long id = getCurrentUser().getId();
        LoginUserVO loginUserVO = new LoginUserVO();
        User dbUser = super.getById(id);
//        if (Objects.nonNull(dbUser.getAvatar())){
//            SysFile sysFile = fileDao.selectById(dbUser.getAvatar());
//            loginUserVO.setFile(sysFile);
//        }
        BeanUtils.copyProperties(dbUser,loginUserVO);
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.lambda().eq(UserRole::getUserId, id);
        List<UserRole> userRoles = userRoleDao.selectList(userRoleQueryWrapper);
        if (userRoles.size() > 0){
            List<Long> roleIds = userRoles.stream().map(userRole -> userRole.getRoleId()).collect(Collectors.toList());
            if (roleIds.size() > 0){
                List<Role> roles = roleDao.selectBatchIds(roleIds);
                loginUserVO.setRoles(roles);
            }
            Set<Long> permissionIds = new HashSet<>();
            roleIds.stream().forEach(aLong -> {
                QueryWrapper<RolePermission> rolePermissionQueryWrapper = new QueryWrapper<>();
                rolePermissionQueryWrapper.lambda().eq(RolePermission::getRoleId, aLong);
                List<RolePermission> rolePermissions = rolePermissionDao.selectList(rolePermissionQueryWrapper);
                if (rolePermissions.size() > 0){
                    List<Long> ids = rolePermissions.stream().map(
                            rolePermission -> rolePermission.getPermissionId()).collect(Collectors.toList());
                    permissionIds.addAll(ids);
                }
            });
            List<Permission> permissions = permissionDao.selectBatchIds(permissionIds);
            List<Permission> permissionList = new ArrayList<>();
            for (Permission permission : permissions) {
                if (permission.getLevel().equals("1")){
                    getPermissionList(permission, permissions);
                    permissionList.add(permission);
                }
            }
            loginUserVO.setPermissionList(permissionList);
        }
        return loginUserVO;
    }

//    @Override
//    public Boolean logout() {
//        Long id = getCurrentUser().getUser().getId();
//        // 生成token
//        return redisCache.deleteObject("login:" + id);
//    }
//
    @Override
    public Boolean reg(User user) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername());
        User dbUser = userDao.selectOne(wrapper);
        if (Objects.nonNull(dbUser)){
            return false;
        }
        String inputPassword = user.getPassword();
        String encodePassword = passwordEncoder.encode(inputPassword);
        user.setPassword(encodePassword);
//        UserVo userVo = new UserVo();
//        BeanUtils.copyProperties(user, userVo);
        return SqlHelper.retBool(userDao.insert(user));
//        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        userLambdaQueryWrapper.eq(User::getUsername, user.getUsername());
//        User dbUser = userDao.selectOne(userLambdaQueryWrapper);
//        if (Objects.nonNull(dbUser)){
//            throw new ServiceException("用户名已存在");
//        }
//        String password = user.getPassword();
//        String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
//        //加密
//        SimpleHash simpleHash = new SimpleHash("md5", password, salt,1);
//        String newPassword = simpleHash.toString();
//        user.setPassword(newPassword);
//        user.setSalt(salt);
//        return super.save(user);
    }

    @Override
    public Boolean updatePassword(User user) {
//        User currentUser = (User) SecurityUtils.getSubject().getSession().getAttribute("userInfo");
        Long userId = getCurrentUser().getId();
        User dbUser = super.getById(userId);
        String newPassword = passwordEncoder.encode(user.getPassword());
//        String salt = dbUser.getSalt();
//        SimpleHash simpleHash = new SimpleHash("md5", user.getPassword(), salt,1);
//        String newPassword = simpleHash.toString();
        dbUser.setPassword(newPassword);
        return super.updateById(dbUser);
    }

    @Override
    public User selectByUsername(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        return userDao.selectOne(wrapper);
    }

    @Override
    public UserVO getByCurrentUser() {
        Long id = getCurrentUser().getId();
        UserVO userVO = new UserVO();
        User dbUser = super.getById(id);
        BeanUtils.copyProperties(dbUser, userVO);
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id", id);
        List<UserRole> userRoles = userRoleDao.selectList(userRoleQueryWrapper);
        if (userRoles.size() > 0){
            List<Long> roleIds = userRoles.stream().map(
                    userRole -> userRole.getRoleId()).collect(Collectors.toList());
            if (roleIds.size() > 0){
                List<Role> roles = roleDao.selectBatchIds(roleIds);
                userVO.setRoles(roles);
            }
        }
        return userVO;
    }

    private void getPermissionList(Permission permission, List<Permission> permissions){
        List<Permission> sonPermissionList = new ArrayList<>();
        for (Permission bean : permissions) {
            if (permission.getId().equals(bean.getPid())){
                sonPermissionList.add(bean);
            }
        }
        permission.setSonPermissionList(sonPermissionList);
        if (sonPermissionList.size() > 0){
            for (Permission permission1 : sonPermissionList) {
                getPermissionList(permission1, sonPermissionList);
            }
        }
    }
}

